﻿/* ***** BEGIN LICENSE BLOCK *****
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 * 
 * The Original Code is CnCNet Server code, Released 30th December 2009.
 * 
 * The Initial Developers of the Original Code are
 * Adam Krock and John Sanderson. Portions created by
 * the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Adam Krock, John Sanderson.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK *****/

using System;
using System.Runtime.InteropServices;

namespace cncNetServer
{
    public class codec
    {
        public static readonly int CLIENT_PACKET = 17970176;
        public static readonly int SERVER_PACKET = 1192961;
        public static readonly int REPLY_PACKET = 34747393;
        public static readonly ushort INFO_END = 43521;



        // String structure with byte header/length
        public struct pString
        {
            public byte myLength;
            public string myString;

            public pString(byte l, string s)
            {
                myLength = l;
                myString = s;
            }
        }

        // Basic packet class
        public class packet
        {
            protected byte[] PACKET_DATA;
            private System.IO.MemoryStream packetStream;
            private System.IO.BinaryReader packetReader;

            public void setData(byte[] b)
            {
                // Start with empty array
                PACKET_DATA = b;
                // Assign reference for memory reader
                packetStream = new System.IO.MemoryStream(PACKET_DATA);
                // Assing reference for Binary reader
                packetReader = new System.IO.BinaryReader(packetStream);
            }
          
            // Adds a value to the packetData
            private void addValue(byte[] b)
            {
                // Copy old array
                byte[] tempOne = PACKET_DATA;
                // Resize array to fit new value
                PACKET_DATA = new byte[tempOne.Length + b.Length];
                // copy old values to the new array
                // If this is not first value, copy
                if (tempOne.Length > 0)
                {
                    // Copy old set
                    Array.Copy(tempOne, PACKET_DATA, tempOne.Length);
                    // Add new set to end				
                    int tempTwo = 0;
                    // Starting at end of current array
                    for (int i = tempOne.Length; i < PACKET_DATA.Length; i++)
                    {
                        // Copy contents from b to the end of packetData
                        PACKET_DATA[i] = b[tempTwo];
                        tempTwo++;
                    }
                }
                else
                {
                    // If this is first value, copy byte directly to data
                    PACKET_DATA = b;
                }
            }

            // Add methods
            public void addByte(byte b)
            {
                addValue(new byte[] { b });
            }

            public void addShort(short s)
            {
                addValue(BitConverter.GetBytes(s));
            }

            public void addUShort(ushort us)
            {
                addValue(BitConverter.GetBytes(us));
            }

            public void addInt(int i)
            {
                addValue(BitConverter.GetBytes(i));
            }

            public void addUInt(uint ui)
            {
                addValue(BitConverter.GetBytes(ui));
            }

            public void addLong(long l)
            {
                addValue(BitConverter.GetBytes(l));
            }

            public void addULong(ulong ul)
            {
                addValue(BitConverter.GetBytes(ul));
            }

            public void addString(string s)
            {
                if (byte.MaxValue > s.Length)
                {
                    addByte((byte)s.Length);
                    addValue(System.Text.ASCIIEncoding.ASCII.GetBytes(s));
                }
            }

            public void addZeroBytes(byte length)
            {
                for (int i = 0; i < length; i++)
                {
                    addByte(0);
                }
            }

            public void addBytes(byte[] b)
            {
                for (int i = 0; i < b.Length; i++)
                {
                    addByte(b[i]);
                }
            }

            // Get methods		
            public byte getByte()
            {
                return packetReader.ReadByte();
            }

            public short getShort()
            {
                return packetReader.ReadInt16();
            }

            public ushort getUShort()
            {
                return packetReader.ReadUInt16();
            }

            public short getNShort()
            {
                byte[] tempOne = packetReader.ReadBytes(2);
                Array.Reverse(tempOne);
                return BitConverter.ToInt16(tempOne, 0);
            }

            public ushort getNUShort()
            {
                byte[] tempOne = packetReader.ReadBytes(2);
                Array.Reverse(tempOne);
                return BitConverter.ToUInt16(tempOne, 0);
            }

            public int getInt()
            {
                return packetReader.ReadInt32();
            }

            public uint getUInt()
            {
                return packetReader.ReadUInt32();
            }

            public int getNInt()
            {
                byte[] tempOne = packetReader.ReadBytes(4);
                Array.Reverse(tempOne);
                return BitConverter.ToInt32(tempOne, 0);
            }
            
            public uint getNUInt()
            {
                 byte[] tempOne = packetReader.ReadBytes(4);
                Array.Reverse(tempOne);
                return BitConverter.ToUInt32(tempOne, 0);
            }

            public long getLong()
            {
                return packetReader.ReadInt64();
            }

            public ulong getULong()
            {
                return packetReader.ReadUInt64();
            }

            public long getNLong()
            {
                byte[] tempOne = packetReader.ReadBytes(8);
                Array.Reverse(tempOne);
                return BitConverter.ToInt64(tempOne, 0);
            }
            
            public ulong getNULong()
            {
                 byte[] tempOne = packetReader.ReadBytes(8);
                Array.Reverse(tempOne);
                return BitConverter.ToUInt64(tempOne, 0);
            }

            public pString getString()
            {
                byte tempOne = getByte();
                byte[] tempTwo = packetReader.ReadBytes(tempOne);
                string tempThree = System.Text.ASCIIEncoding.ASCII.GetString(tempTwo);
                return new pString(tempOne, tempThree);
            }
            public pString getString(byte length)
            {
                byte[] tempOne = packetReader.ReadBytes(length);
                string tempTwo = System.Text.ASCIIEncoding.ASCII.GetString(tempOne);
                return new pString(length, tempTwo);
            }

            public byte[] getBytes()
            {
                return PACKET_DATA;
            }
        }



        // UDP Packet
        public class udpPacket : packet
        {
            // IP
            public byte IPVerLen;
            public byte IPTOS;
            public ushort IPLength;
            public ushort IPID;
            public ushort IPOffset;
            public byte IPTTL;
            public byte IPProtocol;
            public ushort IPChecksum;
            public int IPSrcAddr;
            public int IPDestAddr;
            // UDP
            public ushort UDPsourcePort;
            public ushort UDPdestPort;
            public ushort UDPLength;
            public ushort UDPcheckSum;

            public udpPacket(byte[] b)
            {
                setData(b);
                IPVerLen = getByte();
                IPTOS = getByte();
                IPLength = getUShort();
                IPID = getUShort();
                IPOffset = getUShort();
                IPTTL = getByte();
                IPProtocol = getByte();
                IPChecksum = getUShort();
                IPSrcAddr = getInt();
                IPDestAddr = getInt();

                // UDP header section
                UDPsourcePort = getNUShort();
                UDPdestPort = getNUShort();
                UDPLength = getNUShort();
                UDPcheckSum = getNUShort();
            }
        }

        // Raw cnc Packet
        public class rawCncPacket : packet
        {
            // IP
            public byte IPVerLen;
            public byte IPTOS;
            public ushort IPLength;
            public ushort IPID;
            public ushort IPOffset;
            public byte IPTTL;
            public byte IPProtocol;
            public ushort IPChecksum;
            public int IPSrcAddr;
            public int IPDestAddr;
            // UDP
            public ushort UDPsourcePort;
            public ushort UDPdestPort;
            public ushort UDPLength;
            public ushort UDPcheckSum;
            // CNC
            public int CNCpacketDirection;
            public int CNCpacketNumber;
            public int CNCpacketSource;
            public int CNCpacketDest;
            public ushort CNCpacketPort;
            public ushort CNCpacketHeaderEnd;
            // Data
            public byte dataType; // 1
            public pString dataSender; // 12
            public pString dataMessage; // 24
            public int dataPackOne;
            public int dataPackTwo;
            public byte dataPackEnd;


            public rawCncPacket(byte[] b)
            {
                setData(b);
                IPVerLen = getByte();
                IPTOS = getByte();
                IPLength = getUShort();
                IPID = getUShort();
                IPOffset = getUShort();            
                IPTTL = getByte();
                IPProtocol = getByte();
                IPChecksum = getUShort();
                IPSrcAddr = getInt();
                IPDestAddr = getInt();
                
                // UDP header section
                UDPsourcePort = getNUShort();
                UDPdestPort = getNUShort();
                UDPLength = getNUShort();
                UDPcheckSum = getNUShort();
                
                // CNC header section
                CNCpacketDirection = getInt();
                CNCpacketNumber = getInt();
                CNCpacketSource = getInt();
                CNCpacketDest = getInt();
                CNCpacketPort = getUShort();
                CNCpacketHeaderEnd = getUShort();

                // Data section               
                dataType = getByte();
                dataSender = getString(12);
                dataMessage = getString(24);
                dataPackOne = getInt();
                dataPackTwo = getInt();
                dataPackEnd = getByte();
            }
        }

        // Initial broadcast
        public class broadCastOne : packet
        {
            public int packetType;
            public int packetNumber;
            public int packetSource;
            public int packetDestination;
            public short packetPort;
            public ushort packetInfoEnd;
            public byte packetId;

            public broadCastOne(int number)
            {
                addInt(CLIENT_PACKET);
                addInt(number);
                addInt(-1);
                addInt(-1);
                addShort(-1);
                addUShort(INFO_END);
                addByte(0);       
                addZeroBytes(45);
            }

            public broadCastOne(byte[] b) 
            {
                setData(b);
                packetType = getInt();
                packetNumber = getInt();
                packetSource = getInt();
                packetDestination = getInt();
                packetPort = getShort();
                packetInfoEnd = getUShort();
                packetId = getByte();
            }
        }

        public class decode
        {
            // Decode packet
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct clientRegistration
            {
                public byte packetId;
                public byte[] senderNameBytes;
                public string senderName; // 11
                public byte[] senderPasswordBytes;
                public string senderPassword; // 11         
                public short senderPort;

                public clientRegistration(byte[] packet)
                {
                    System.IO.MemoryStream stm = new System.IO.MemoryStream(packet, 0, packet.Length);
                    System.IO.BinaryReader rdr = new System.IO.BinaryReader(stm);
                    packetId = rdr.ReadByte();
                    senderNameBytes = rdr.ReadBytes(11);
                    senderName = System.Text.ASCIIEncoding.ASCII.GetString(senderNameBytes);
                    senderPasswordBytes = rdr.ReadBytes(11);
                    senderPassword = System.Text.ASCIIEncoding.ASCII.GetString(senderPasswordBytes);
                    senderPort = rdr.ReadInt16();
                }
            }




        }

        public class encode
        {
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct clientRegistration
            {
                public byte packetId;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                public string senderName; // 11
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
                public string senderPassword; // 11         
                public short senderPort;

                public clientRegistration(string name, string password, short port)
                {
                    packetId = 117;
                    senderName = name;
                    senderPassword = password;
                    senderPort = port;
                }
            }

            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct clientList
            {
                public short myClientNumber;
                public clientRegistration[] myClients;

                public clientList(short numOfClients)
                {
                    myClientNumber = numOfClients;
                    myClients = new clientRegistration[1];
                }

                public void addClient(clientRegistration cR)
                {
                    if (myClients.Length < 2)
                    {
                        // Copy old array into temp
                        clientRegistration[] tempOne = myClients;
                        // Set new size
                        myClients = new clientRegistration[myClients.Length + 1];

                        // Set new client as first
                        myClients[0] = cR;
                        // copy old clients into rest of array

                        for (int i = 1; i < myClients.Length; i++)
                        {
                            myClients[i] = tempOne[i - 1];
                        }

                    }
                    else
                    {
                        myClients[0] = cR;
                    }
                }
            }
        }

       
    }
}
